using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace XnaDevRu.BulletX
{
	public class XnaDebugDraw : IDebugDraw
	{
		DebugDrawModes _debugDrawModes = DebugDrawModes.NoDebug;
		GraphicsDevice _graphicsDevice;
		List<VertexPositionColor> _vertices = new List<VertexPositionColor>();
		VertexPositionColor[] _lineVertices = new VertexPositionColor[2];
        BasicEffect _basicEffect;

		public XnaDebugDraw(GraphicsDevice device)
		{
			this._graphicsDevice = device;
            this._basicEffect = new BasicEffect(device, null);
            this._graphicsDevice.VertexDeclaration = new VertexDeclaration(device, VertexPositionColor.VertexElements);
		}

		public void DrawAabb(Vector3 from, Vector3 to, Vector3 color)
		{
			Vector3 halfExtents = (to - from) * 0.5f;
			Vector3 center = (to + from) * 0.5f;

			Vector3 edgecoord = new Vector3(1f, 1f, 1f), pa, pb;
			for (int i = 0; i < 4; i++)
			{
				for (int j = 0; j < 3; j++)
				{
					pa = new Vector3(edgecoord.X * halfExtents.X, edgecoord.Y * halfExtents.Y,
						edgecoord.Z * halfExtents.Z);
					pa += center;

					int othercoord = j % 3;
					MathHelper.SetElement(ref edgecoord, othercoord, MathHelper.GetElement(edgecoord, othercoord) * -1f);
					pb = new Vector3(edgecoord.X * halfExtents.X, edgecoord.Y * halfExtents.Y,
						edgecoord.Z * halfExtents.Z);
					pb += center;

					DrawLine(pa, pb, color);
				}
				edgecoord = new Vector3(-1f, -1f, -1f);
				if (i < 3)
					MathHelper.SetElement(ref edgecoord, i, MathHelper.GetElement(edgecoord, i) * -1f);
			}
		}

        public void Update(Matrix view, Matrix projection)
        {
            this._basicEffect.AmbientLightColor = new Vector3(1, 1, 1);

            this._basicEffect.View = view;
            this._basicEffect.Projection = projection;
        }

		/// <summary>
		/// Put this between effect.
		/// </summary>
		public void DrawAll()
		{
            this._basicEffect.Begin();
            foreach (EffectPass pass in this._basicEffect.CurrentTechnique.Passes)
            {
                pass.Begin();

                if (_vertices.Count > 1)
                {
                    _graphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, _vertices.ToArray(), 0, _vertices.Count / 2);
                    _vertices.Clear();
                }
                if (_lineVertices[0] != default(VertexPositionColor))
                    _graphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, _lineVertices, 0, 1);

                pass.End();
            }
            this._basicEffect.End();
		}

		#region IDebugDraw Members

		public void DrawLine(Vector3 from, Vector3 to, Vector3 color)
		{
			if ((int)_debugDrawModes > 0)
			{
                this._basicEffect.Begin();
                foreach (EffectPass pass in this._basicEffect.CurrentTechnique.Passes)
                {
                    pass.Begin();

                    _lineVertices[0] = new VertexPositionColor(from, new Color(color));
                    _lineVertices[1] = new VertexPositionColor(to, new Color(color));
                    
                    _graphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, _lineVertices, 0, 1);

                    pass.End();
                }
                this._basicEffect.End();
            
            }
		}

		public void DrawContactPoint(Vector3 pointOnB, Vector3 normalOnB, float distance, int lifeTime, Vector3 color)
		{
			if ((_debugDrawModes & DebugDrawModes.DrawContactPoints) != 0)
			{
				Vector3 to = pointOnB + normalOnB * distance;
				Vector3 from = pointOnB;
				//device.RenderState.PointSize = 10; // TODO: Experiment with this
				DrawLine(from, to, color);
			}
		}

		public DebugDrawModes DebugMode { get { return _debugDrawModes; } set { _debugDrawModes = value; } }

		#endregion
	}
}
